package com.crawler.waf.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.accept.ContentNegotiationManager;

import com.crawler.waf.exceptions.handlers.AbstractWafExceptionHandler;
import com.crawler.waf.exceptions.handlers.WafCustomExceptionHandler;
import com.crawler.waf.exceptions.handlers.WafExceptionHandler;
import com.crawler.waf.exceptions.support.WafErrorMessageMapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.crawler.waf.exceptions.MapUtils.putAllIfAbsent;
import static org.springframework.util.StringUtils.hasText;
/**
 * 当前对象实现Waf中特定异常的Handler的映射
 *
 */
public class WafHandlerExceptionResolverBuilder {


	private final Map<Class, WafExceptionHandler> exceptionHandlers = new HashMap<>();

	private MediaType defaultContentType;

	private ContentNegotiationManager contentNegotiationManager;

	/**
	 * 类型转换器
	 */
	private List<HttpMessageConverter<?>> httpMessageConverters;


	/**
	 * 使用默认的handler
	 */
	private boolean withDefaultHandlers = true;



	public WafHandlerExceptionResolver build() {

		if (withDefaultHandlers) {
			// 增加默认的handler
			putAllIfAbsent(exceptionHandlers, getDefaultHandlers()); 
		}


		WafHandlerExceptionResolver resolver = new WafHandlerExceptionResolver();
		resolver.setExceptionHandlers((Map) exceptionHandlers);

		if (httpMessageConverters != null) {
			resolver.setMessageConverters(httpMessageConverters); 
		}
		if (contentNegotiationManager != null) {
			resolver.setContentNegotiationManager(contentNegotiationManager);
		}
		if (defaultContentType != null) {
			resolver.setDefaultContentType(defaultContentType);
		}
		resolver.afterPropertiesSet();

		return resolver;
	}

	/**
	 * 默认的媒体类型支持
	 */
	public WafHandlerExceptionResolverBuilder defaultContentType(
			MediaType mediaType) {
		this.defaultContentType = mediaType;
		return this;
	}

	/**
	 * 默认的媒体类型支持
	 */
	public WafHandlerExceptionResolverBuilder defaultContentType(
			String mediaType) {
		defaultContentType(hasText(mediaType) ? MediaType
				.parseMediaType(mediaType) : null);
		return this;
	}

	/**
	 * 注册给定的异常类
	 */
	public WafHandlerExceptionResolverBuilder addHandler(
			Class<?> exceptionClass,
			WafExceptionHandler exceptionHandler) {

		exceptionHandlers.put(exceptionClass, exceptionHandler);
		return this;
	}

	/**
	 * 增加异常和异常捕获类到Map中
	 */
	public  WafHandlerExceptionResolverBuilder addHandler(
			AbstractWafExceptionHandler exceptionHandler) {

		return addHandler(exceptionHandler.getExceptionClass(),
				exceptionHandler);
	}

	/**
	 * 注册异常和异常捕获类
	 *
	 * @param exceptionClass
	 *            异常类型
	 * @param status
	 *            http状态码.
	 */
	public WafHandlerExceptionResolverBuilder addErrorMessageHandler(
			Class<?> exceptionClass, HttpStatus status) {

		return addHandler(new WafCustomExceptionHandler(
				exceptionClass, status));
	}

	@SuppressWarnings("rawtypes")
	private Map<Class, WafExceptionHandler> getDefaultHandlers() {
		Map<Class, WafExceptionHandler> map = new HashMap<>();
		
		for (WafErrorMessageMapper item : WafErrorMessageMapper.values()) {
			addHandler(item.getExClass(), item.getHandler());
		}

		return map;
	}

	@SuppressWarnings("unused")
	private void addHandlerTo(Map<Class<?>, WafExceptionHandler> map,
			Class<?> exceptionClass, HttpStatus status) {
		map.put(exceptionClass, new WafCustomExceptionHandler(
				exceptionClass, status));
	}

	public MediaType getDefaultContentType() {
		return defaultContentType;
	}

	public void setDefaultContentType(MediaType defaultContentType) {
		this.defaultContentType = defaultContentType;
	}

	public ContentNegotiationManager getContentNegotiationManager() {
		return contentNegotiationManager;
	}

	public void setContentNegotiationManager(
			ContentNegotiationManager contentNegotiationManager) {
		this.contentNegotiationManager = contentNegotiationManager;
	}

	public List<HttpMessageConverter<?>> getHttpMessageConverters() {
		return httpMessageConverters;
	}

	public void setHttpMessageConverters(
			List<HttpMessageConverter<?>> httpMessageConverters) {
		this.httpMessageConverters = httpMessageConverters;
	}


	public boolean isWithDefaultHandlers() {
		return withDefaultHandlers;
	}

	public void setWithDefaultHandlers(boolean withDefaultHandlers) {
		this.withDefaultHandlers = withDefaultHandlers;
	}

	public Map<Class, WafExceptionHandler> getExceptionHandlers() {
		return exceptionHandlers;
	}

}
